﻿#include "ench264.h"
 
#include <QCoreApplication>
#include "mainwindow.h"
#include <QDebug>

extern "C"
{
#include "img_conv.h"
}

 #ifdef  LINUX_AARCH64
//
//                 *H.264 profile_idc parameter
//                 *66  - Baseline profile
//                 *77  - Main profile
//                 *100 - High profile
// mpp mpp_enc_cfg_set_s32(pstEncH265->cfg, "h264:profile", 66);
//42A01E --baseline
//
//64001f （High Profile + Level 3.1）
//640016 （High Profile + Level 2.2）
//640c34 （Constrained High Profile + Level 5.2）
//42801e （Baseline Profile + Level 3.0）



#include "im2d.h"
#include "RgaUtils.h"
#endif
#include "libyuv.h"

MediaEncIR::MediaEncIR(QObject *parent)
{

   m_AppPath = QCoreApplication::applicationDirPath();

   m_parent = parent;
   m_nFrameIn = 0;
   m_nFrameOut = 0;
   m_nFps = 0;




   m_ThreadRun = true;



   nWidth = 640;
   nHeight = 512;


   int   nChannel = 0;
   int   nRes = 0;

   m_hasSpsHead = false;
   nFps = 25;

    pMainGUI = reinterpret_cast<MainWindow*>(m_parent);

    rtspInst = create_rtsp_demo(8555,20000);
    rtspSession = create_rtsp_session(rtspInst,cRtspURL,RTSP_CODEC_ID_VIDEO_H264);


    nPts = 0;
    pImg = new uint8_t[INFRARED_MAX_LEN];
    pH265Packet = (uint8_t*)malloc(INFRARED_MAX_LEN/2);

    x264_param_t param;
    nRes = x264_param_default_preset(&param, "superfast", NULL);
    param.i_bitdepth = 8;//编码位数
    param.i_csp = X264_CSP_I420;//编码制式
    param.rc.i_qp_min = 36;//编码质量：越小，视频质量损失越小
    param.rc.i_qp_max = 40;
    param.rc.i_qp_step = 2;
    param.i_width = nWidth;//分辨率
    param.i_height = nHeight;
    param.i_fps_den = 1;//帧率
    param.i_fps_num = 25;
    param.i_keyint_max = 4;//设置IDR关键帧间隔
    param.i_keyint_min = 1;
    param.b_vfr_input = 0;//固定帧率
    param.b_repeat_headers = 1;//在每个关键帧前放置SPS/PPS
    param.b_annexb = 1;//在NAL单元前放置起始码
    nRes = x264_param_apply_profile(&param, "baseline");



    nRes = x264_picture_alloc(&inputpic, param.i_csp, param.i_width, param.i_height);
    //打开编码器
    m_hX264Enc  = x264_encoder_open(&param);

    moveToThread(this);
}




MediaEncIR::~MediaEncIR()
{
    if(rtspSession) {
        rtsp_del_session(rtspSession);
    }

    rtsp_del_demo(rtspInst);

    x264_encoder_close(m_hX264Enc);
    x264_picture_clean(&inputpic);


    SAFE_DELETE_ARRAY(pImg);
    SAFE_DELETE_ARRAY(pH265Packet);

    log_i("~MediaEnc()");
}




void MediaEncIR::run()
{
   exec();
   log_i("MediaEnc proc is exit");
}

void MediaEncIR::Stop()
{
    quit();
}


void MediaEncIR::EncSendOneFrame()
{
    int nPackLen = 0;
    int j = 0;
    x264_nal_t *nal;
    int i_nal;
    int i_frame_size = 0;

    if(m_hasSpsHead == false)
    {
        i_frame_size = x264_encoder_headers(m_hX264Enc, &nal, &i_nal);
        if(i_frame_size < 0)
            return;

        memcpy(pH265Packet,nal->p_payload, i_frame_size);
        nPackLen+=i_frame_size;
        m_hasSpsHead = true;
    }

     i_frame_size = x264_encoder_encode(m_hX264Enc, &nal, &i_nal, &inputpic, &pic_out);
     if(i_frame_size > 0)
     {
         memcpy(pH265Packet+nPackLen,nal->p_payload, i_frame_size);
         nPackLen+=i_frame_size;
     }


    if(nPackLen > 0)
    {
        //debug for write file
        //fwrite(pH265Packet,nPackLen,1,fp_output);


        //rtsp_sever_tx_video(rtspInst,
        //           rtspSession,
        //           pH265Packet,nPackLen,
        //           nPts);

        nPts += 1000000/nFps;
        rtpPackSeq = rtpPackSeq + 1;

    }

}



void MediaEncIR::EncoderFrame(uint8_t* pImgData,int nLength,int nErrCode)
{


    int   nPackLen = 0;
    int nLen = nLength;
    memcpy(pImg,pImgData,nLength);
    //ldMemSet(pImg,128,nLen);



   //================cpu versin rgb24 to yuv420p ============================
     libyuv::RGB24ToI420(pImg,nWidth*3,
                        inputpic.img.plane[0],nWidth,
                        inputpic.img.plane[1],nWidth/2,
                        inputpic.img.plane[2],nWidth/2,
                        nWidth,
                        nHeight);




     m_nFrameIn++;
     m_nFps++;



   if(nErrCode == LD_RES_CAMERA_ERR)
   {
       int i=0;
       for(i=0; i<60; i++)
       {//错误一秒检查到，错误不自动更新输出,给远端发20帧，远端好更新，太多没意义
          EncSendOneFrame();
       }
   }
   else
   {
       EncSendOneFrame();
   }

}

